﻿using Core;
using Core.Data;
using Core.Domain.Stores;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Services.Stores
{
    public partial class StoreMappingService : IStoreMappingService
    {
        #region Fields

        private readonly IRepository<StoreMapping> _storeMappingRepository;
        private readonly IStoreContext _storeContext;

        #endregion

        #region Ctor

        /// <summary>
        /// Ctor
        /// </summary>
        public StoreMappingService(IStoreContext storeContext,
            IRepository<StoreMapping> storeMappingRepository)
        {
            this._storeContext = storeContext;
            this._storeMappingRepository = storeMappingRepository;
        }

        #endregion

        #region Methods

        public virtual void DeleteStoreMapping(StoreMapping storeMapping)
        {
            if (storeMapping == null)
                throw new ArgumentNullException("storeMapping");

            _storeMappingRepository.Delete(storeMapping);

        }

        public virtual StoreMapping GetStoreMappingById(int storeMappingId)
        {
            if (storeMappingId == 0)
                return null;

            return _storeMappingRepository.GetById(storeMappingId);
        }

        public virtual IList<StoreMapping> GetStoreMappings<T>(T entity) where T : BaseEntity
        {
            if (entity == null)
                throw new ArgumentNullException("entity");

            int entityId = entity.Id;
            string entityName = typeof(T).Name;

            var query = from sm in _storeMappingRepository.Table
                        where sm.EntityId == entityId &&
                        sm.EntityName == entityName
                        select sm;
            var storeMappings = query.ToList();
            return storeMappings;
        }


        public virtual void InsertStoreMapping(StoreMapping storeMapping)
        {
            if (storeMapping == null)
                throw new ArgumentNullException("storeMapping");

            _storeMappingRepository.Insert(storeMapping);
        }

        public virtual void InsertStoreMapping<T>(T entity, int storeId) where T : BaseEntity
        {
            if (entity == null)
                throw new ArgumentNullException("entity");

            if (storeId == 0)
                throw new ArgumentOutOfRangeException("storeId");

            int entityId = entity.Id;
            string entityName = typeof(T).Name;

            var storeMapping = new StoreMapping()
            {
                EntityId = entityId,
                EntityName = entityName,
                StoreId = storeId
            };

            InsertStoreMapping(storeMapping);
        }

        public virtual void UpdateStoreMapping(StoreMapping storeMapping)
        {
            if (storeMapping == null)
                throw new ArgumentNullException("storeMapping");

            _storeMappingRepository.Update(storeMapping);

        }

        public virtual int[] GetStoresIdsWithAccess<T>(T entity) where T : BaseEntity
        {
            if (entity == null)
                throw new ArgumentNullException("entity");

            int entityId = entity.Id;
            string entityName = typeof(T).Name;

            var query = from sm in _storeMappingRepository.Table
                        where sm.EntityId == entityId &&
                        sm.EntityName == entityName
                        select sm.StoreId;
            var result = query.ToArray();
            if (result == null)
                result = new int[0];
            return result;
        }

        public virtual bool Authorize<T>(T entity) where T : BaseEntity
        {
            return Authorize(entity, _storeContext.CurrentStore.Id);
        }

        public virtual bool Authorize<T>(T entity, int storeId) where T : BaseEntity
        {
            if (entity == null)
                return false;

            if (storeId == 0)
                return true;

            foreach (var storeIdWithAccess in GetStoresIdsWithAccess(entity))
                if (storeId == storeIdWithAccess)
                    return true;

            return false;
        }

        #endregion
    }
}
